Skip to content

开启Web站点的http2协议

目前国内许多主流的站点都开始开启了H2协议,http2协议的优势不言而喻,能加快网络传输效率,提升Web服务的访问效率。 那么如何开启http2协议呢,本文就以 Nginx 搭建的站点为例,详细说一下怎么一步步实现支持H2协议的 Web站点。

相关背景

在当前无论是国内还是国外,相当多的主流网站或APP都开始支持HTTP2协议了。 以下测试了淘宝、抖音、github三家站点,它们都开启了HTTP2协议了。

Alt text

目前 客户端浏览器对 H2协议的支持情况怎么样呢?

Alt text

从上图可以看出,除了IE11以下的浏览器不支持 Http2 协议,几乎所有的浏览器都支持了,将近 97% 的支持率说明没有什么兼容性问题了。

H2协议简介

什么是http2协议?

http/2 is a replacement for how http is expressed “on the wire.” It is not a ground-up rewrite of the protocol; http methods, status codes and semantics are the same, and it should be possible to use the same APIs as http/1.x (possibly with some small additions) to represent the protocol.

从官网的描述中,我们可以看出:

  • 对1.x协议语意的完全兼容

2.0协议是在1.x基础上的升级而不是重写,1.x协议的方法,状态及api在2.0协议里是一样的

The focus of the protocol is on performance; specifically, end-user perceived latency, network and server resource usage. One major goal is to allow the use of a single connection from browsers to a Web site.

  • 主要目标是提升性能

让终端用户使用网络服务,访问网络资源,没有那么高的延迟,能及时给出请求的响应内容,优化性能。 在一个TCP链接中,就能够完成终端和站点之间的通信。

H2优化的内容有很多,我们就不一一展开了,文末有相关的链接,感兴趣的话可以点开细读。

  • 二进制分帧(Binary Format)设计
  • 多路复用 (Multiplexing) / 连接共享
  • 头部压缩(Header Compression)
  • 服务端推送(Server Push)
  • 。。。。。。

接下来我们进入开启http2协议的流程中。

整体的流程

必备的条件

开启H2协议,需要一下必备条件:

  • 先有个域名(需要购买了,有很多便宜的几块钱一年的)
  • 获得 SSL 证书(如何获得下面介绍)
  • Nginx的版本高于 1.9.5(其它Web服务器软件如Apache,需要自行查看一下)
  • 开启相关的 Nginx 的模块 和 配置

整体流程

整个流程如下:

  1. 先获得 SSL 证书
  2. 使用 SSL证书,开启 HTTPS协议
  3. 配置 H2 协议
  4. 重新载入配置,启动 Web server
  5. 测试效果

Alt text

获得SSL证书

如何获得 SSL 证书呢?

有多种方式,看个人的需求。如果是工作上的Web服务,有真实的消费用户,那还是购买正规的SSL证书比较好。 SSL证书的种类也是多种多样的,当然价格越高支持的特性越多,提供的安全性会更好些。以下是国内某云厂商提供的各种 SSL 证书的规格说明,用以满足不同场景下的业务需求。

Alt text

本文的目的是研究和学习,咱们就申请一个免费的 SSL 证书,来做一下试验。 获得免费证书的途径也有很多的,许多国内外的云厂家(阿里、腾讯、华为、亚马逊等)都提供免费的SSL证书的。 在文末的链接中,提供了三个获得免费SSL证书的网址,需要的小伙伴们自取。

一般在申请的过程中,需要填写一下您的域名、个人联系方式,很简单的。

Alt text

填写完成后,大约 2 ~ 3 分钟后,就会收到证书通知,产生下面的一条记录。 展示是免费的SSL证书,到期时间,并提供证书的下载入口。

Alt text

我们点击“下载”,选择 Nginx 格式的证书文件。

Alt text

我们将下载后的证书文件保存到本地磁盘,其中包括证书以及秘钥两个文件。

Alt text

接下来,我们将证书文件上传到服务器的 Nginx 目录下面

上传SSL证书

将本地的证书上传到服务器有多种方式,包括rz、FTP、SFTP等等,我们这里使用 rz 上传。 使用 rz 上传前,要确保先安装了 lrzsz 这个工具。 lrzsz 这个工具专门用于远程传输文件的,其中 rz 是从本地上传文件到服务器, sz 是从远程服务下载文件到本地。如果本地使用的是 苹果Mac系统的电脑,远程服务器是 Linux 系统,Shell 用的是 iTerm2,可以参照下面的方式配置一下 rz 的环境:

配置 rz、sz上传下载

  • 在远程服务器(centos)上安装lrzsz:yum install lrzsz
  • 在本地的Mac 系统中安装 lrzsz工具:brew install lrzsz
  • 按照下图所示,设置一下iTerm2 的触发器,目的是在接收或发送文件时能和系统的文件管理器交互

Alt text

具体填写的内容:

Regular ExpressionActionParameters
\*\*B0100 Run Silent Coprocess/usr/local/bin/iterm2-send-zmodem.sh
\*\*B00000000000000Run Silent Coprocess/usr/local/bin/iterm2-recv-zmodem.sh

这样当我们在 iTerm2 的 shell 中执行 rz 上传命令时,就会弹出系统的文件管理窗体了,就可以选择要上传的证书文件了。

关于 iterm2-send-zmodem.sh 和 iterm2-recv-zmodem.sh 两个 shell 脚本的文件内容,需要手动创建到指定的 /usr/local/bin 目录下

iterm2-send-zmodem.sh,通知 iTerm2 在 发送文件时,弹出“选择要发送文件”的系统窗口

sh
#!/bin/bash
# iterm2-send-zmodem.sh 文件的内容:

osascript -e 'tell application "iTerm2" to version' > /dev/null 2>&1 && NAME=iTerm2 || NAME=iTerm
if [[ $NAME = "iTerm" ]]; then
	FILE=`osascript -e 'tell application "iTerm" to activate' -e 'tell application "iTerm" to set thefile to choose file with prompt "Choose a file to send"' -e "do shell script (\"echo \"&(quoted form of POSIX path of thefile as Unicode text)&\"\")"`
else
	FILE=`osascript -e 'tell application "iTerm2" to activate' -e 'tell application "iTerm2" to set thefile to choose file with prompt "Choose a file to send"' -e "do shell script (\"echo \"&(quoted form of POSIX path of thefile as Unicode text)&\"\")"`
fi
if [[ $FILE = "" ]]; then
	echo Cancelled.
	# Send ZModem cancel
	echo -e \\x18\\x18\\x18\\x18\\x18
	sleep 1
	echo
	echo \# Cancelled transfer
else
	/usr/local/bin/sz "$FILE" -e -b
	sleep 1
	echo
	echo \# Received $FILE
fi
#!/bin/bash
# iterm2-send-zmodem.sh 文件的内容:

osascript -e 'tell application "iTerm2" to version' > /dev/null 2>&1 && NAME=iTerm2 || NAME=iTerm
if [[ $NAME = "iTerm" ]]; then
	FILE=`osascript -e 'tell application "iTerm" to activate' -e 'tell application "iTerm" to set thefile to choose file with prompt "Choose a file to send"' -e "do shell script (\"echo \"&(quoted form of POSIX path of thefile as Unicode text)&\"\")"`
else
	FILE=`osascript -e 'tell application "iTerm2" to activate' -e 'tell application "iTerm2" to set thefile to choose file with prompt "Choose a file to send"' -e "do shell script (\"echo \"&(quoted form of POSIX path of thefile as Unicode text)&\"\")"`
fi
if [[ $FILE = "" ]]; then
	echo Cancelled.
	# Send ZModem cancel
	echo -e \\x18\\x18\\x18\\x18\\x18
	sleep 1
	echo
	echo \# Cancelled transfer
else
	/usr/local/bin/sz "$FILE" -e -b
	sleep 1
	echo
	echo \# Received $FILE
fi

iterm2-recv-zmodem.sh,通知 iTerm2 在接收文件时,弹出“选择要接收的目录”的系统窗口

sh
#!/bin/bash
# iterm2-recv-zmodem.sh 文件的内容:

osascript -e 'tell application "iTerm2" to version' > /dev/null 2>&1 && NAME=iTerm2 || NAME=iTerm
if [[ $NAME = "iTerm" ]]; then
	FILE=$(osascript -e 'tell application "iTerm" to activate' -e 'tell application "iTerm" to set thefile to choose folder with prompt "Choose a folder to place received files in"' -e "do shell script (\"echo \"&(quoted form of POSIX path of thefile as Unicode text)&\"\")")
else
	FILE=$(osascript -e 'tell application "iTerm2" to activate' -e 'tell application "iTerm2" to set thefile to choose folder with prompt "Choose a folder to place received files in"' -e "do shell script (\"echo \"&(quoted form of POSIX path of thefile as Unicode text)&\"\")")
fi

if [[ $FILE = "" ]]; then
	echo Cancelled.
	# Send ZModem cancel
	echo -e \\x18\\x18\\x18\\x18\\x18
	sleep 1
	echo
	echo \# Cancelled transfer
else
	cd "$FILE"
	/usr/local/bin/rz -E -e -b --bufsize 4096
	sleep 1
	echo
	echo
	echo \# Sent \-\> $FILE
fi
#!/bin/bash
# iterm2-recv-zmodem.sh 文件的内容:

osascript -e 'tell application "iTerm2" to version' > /dev/null 2>&1 && NAME=iTerm2 || NAME=iTerm
if [[ $NAME = "iTerm" ]]; then
	FILE=$(osascript -e 'tell application "iTerm" to activate' -e 'tell application "iTerm" to set thefile to choose folder with prompt "Choose a folder to place received files in"' -e "do shell script (\"echo \"&(quoted form of POSIX path of thefile as Unicode text)&\"\")")
else
	FILE=$(osascript -e 'tell application "iTerm2" to activate' -e 'tell application "iTerm2" to set thefile to choose folder with prompt "Choose a folder to place received files in"' -e "do shell script (\"echo \"&(quoted form of POSIX path of thefile as Unicode text)&\"\")")
fi

if [[ $FILE = "" ]]; then
	echo Cancelled.
	# Send ZModem cancel
	echo -e \\x18\\x18\\x18\\x18\\x18
	sleep 1
	echo
	echo \# Cancelled transfer
else
	cd "$FILE"
	/usr/local/bin/rz -E -e -b --bufsize 4096
	sleep 1
	echo
	echo
	echo \# Sent \-\> $FILE
fi

上传到服务器

我们登录到远程服务器,进入到Nginx目录下面。

Alt text

  1. 创建一个 cert 目录,用于存放我们刚才下载到本地的 SSL 证书
sh
# 进入到Nginx的配置目录
cd /etc/nginx
# 创建 cert 目录
mkdir cert
# 进入到 cert 目录
cd cert
# 在服务器上执行 rz 命令,上传 SSL 证书文件
rz
# 进入到Nginx的配置目录
cd /etc/nginx
# 创建 cert 目录
mkdir cert
# 进入到 cert 目录
cd cert
# 在服务器上执行 rz 命令,上传 SSL 证书文件
rz

Alt text

如上图所示,这样输入 rz 命令就能调出本地的 选择文件发送 的系统窗体了。 我们选择好SSL证书文件后,就会上传到服务器的指定目录(/etc/nginx/cert)下了。 接下来,我们开始配置Nginx 文件。

配置SSL证书

打开 Nginx的配置文件:

sh
vi nginx.conf
vi nginx.conf

修改如下的配置,主要是配置一下证书的路径,以及域名,监听的端口号。 默认情况下,可能有防火墙的策略,需要打开 443端口的通道,以保证外部的 https请求能进入。

sh
server {
    #HTTPS的默认访问端口443。
    #如果未在此处配置HTTPS的默认访问端口,可能会造成Nginx无法启动。
    listen 443 ssl;
    
    #填写证书绑定的域名
    server_name mawen.tech;

    #填写证书文件名称
    ssl_certificate cert/mawen.tech.pem;
    #填写证书私钥文件名称
    ssl_certificate_key cert/mawen.tech.key;

    ssl_session_cache shared:SSL:1m;
    ssl_session_timeout 5m;
}
server {
    #HTTPS的默认访问端口443。
    #如果未在此处配置HTTPS的默认访问端口,可能会造成Nginx无法启动。
    listen 443 ssl;
    
    #填写证书绑定的域名
    server_name mawen.tech;

    #填写证书文件名称
    ssl_certificate cert/mawen.tech.pem;
    #填写证书私钥文件名称
    ssl_certificate_key cert/mawen.tech.key;

    ssl_session_cache shared:SSL:1m;
    ssl_session_timeout 5m;
}

修改完毕后,执行:wq保持一下配置nginx配置文件,重新加载一个配置

sh
nginx -s reload
nginx -s reload

刷新浏览,可以看到已经是 https 协议的地址了。

Alt text

我们可以更进一步,当访问 http 的地址时,默认转发到 https 协议的地址中,以此来保证站点的内容安全性。

sh
server {
    listen 80;
    #填写证书绑定的域名
    server_name mawen.tech;
    #将所有HTTP请求通过rewrite指令重定向到HTTPS。
    rewrite ^(.*)$ https://$host$1;
    location / {
        index index.html index.htm;
    }
}
server {
    listen 80;
    #填写证书绑定的域名
    server_name mawen.tech;
    #将所有HTTP请求通过rewrite指令重定向到HTTPS。
    rewrite ^(.*)$ https://$host$1;
    location / {
        index index.html index.htm;
    }
}

nginx.conf文件中会存在两个server {}代码段,一个是 80 端口的http请求模块,另一个是 443 端口的 https 请求模块,我们要保证 80 端口的server 代码块 放在 443 端口号的下面。 这样http 到 https的转发请求,才能正常跳转过去。

开启H2协议

开启 http2协议就非常简单了,甚至在新版本的Nginx 中都会默认开启 H2的。 只要在 listen 字段后面,增加 http2的设置即可。

sh
server {
  # 对应 IP4
  listen       443 ssl http2;
  # 对应 IP6
  listen       [::]:443 ssl http2;
}
server {
  # 对应 IP4
  listen       443 ssl http2;
  # 对应 IP6
  listen       [::]:443 ssl http2;
}

这里会有两个 监听,一个对应 IP4的网络地址,另一个对应 IP6的地址。 修改完保存一下,重新加载 Nginx的配置。

sh
nginx -s reload
nginx -s reload

验证一下效果:

Alt text

如上图所示,第二请求的协议地址已经变成h2了,说明我们的修改生效了。 关于Nginx的完整配置,放在文末最后的链接中了,有需要的小伙伴可以查看。

总结

本文主要讲解了如何开启站点的 http2协议,这里的关键是先要支持 https协议,因为 http2时强依赖 https的,没办法直接在 http协议中开启 H2。 所以,需要先拥有SSL证书,配置好 https协议后,才能进行开启 http2协议。 与此同时,我们也简要介绍了 http2协议的优势,如何申请SSL证书,如何上传证书文件以及修改Nginx的配置等。

相关链接